#ifndef _WX_VARIANT_H_
#define _WX_VARIANT_H_

#include "wx/defs.h"
#include "wx/object.h"
#include "wx/string.h"
#include "wx/arrstr.h"
#include "wx/list.h"
#include "wx/cpp.h"
#include "wx/datetime.h"

class wxVariantData: public wxObject {
    friend class wxVariant;
  public:
    wxVariantData(): wxObject(), m_count( 1 ) { }
    virtual bool Eq( wxVariantData& data ) const = 0;
    virtual bool Write( std::ostream& ( str ) ) const { return false; }
    virtual bool Write( wxString& ( str ) ) const { return false; }
    virtual bool Read( std::istream& ( str ) ) { return false; }
    virtual bool Read( wxString& ( str ) ) { return false; }
    virtual wxString GetType() const = 0;
    virtual wxClassInfo* GetValueClassInfo() { return NULL; }

    void IncRef() { m_count++; }
    void DecRef() {
      if( --m_count == 0 ) {
        delete this;
      }
    }

    int GetRefCount() const { return m_count; }

  protected:
    virtual ~wxVariantData() { }

  private:
    int     m_count;

  private:
    DECLARE_ABSTRACT_CLASS( wxVariantData )
};

class wxVariant: public wxObject {
  public:
    wxVariant();

    wxVariant( const wxVariant& variant );
    wxVariant( wxVariantData* data, const wxString& name = wxEmptyString );
    virtual ~wxVariant();

    // generic assignment
    void operator= ( const wxVariant& variant );

    // Assignment using data, e.g.
    // myVariant = new wxStringVariantData("hello");
    void operator= ( wxVariantData* variantData );

    bool operator== ( const wxVariant& variant ) const;
    bool operator!= ( const wxVariant& variant ) const;

    // Sets/gets name
    inline void SetName( const wxString& name ) { m_name = name; }
    inline const wxString& GetName() const { return m_name; }

    // Tests whether there is data
    bool IsNull() const;

    // For compatibility with wxWidgets <= 2.6, this doesn't increase
    // reference count.
    wxVariantData* GetData() const { return m_data; }
    void SetData( wxVariantData* data ) ;

    // make a 'clone' of the object
    void Ref( const wxVariant& clone );
    void UnRef();
    void MakeNull();
    void Clear();
    wxString GetType() const;
    bool IsType( const wxString& type ) const;
    bool IsValueKindOf( const wxClassInfo* type ) const;
    wxString MakeString() const;
    wxVariant( double val, const wxString& name = wxEmptyString );
    bool operator== ( double value ) const;
    bool operator!= ( double value ) const;
    void operator= ( double value ) ;
    inline operator double () const {  return GetDouble(); }
    inline double GetReal() const { return GetDouble(); }
    double GetDouble() const;
    wxVariant( long val, const wxString& name = wxEmptyString );
    wxVariant( int val, const wxString& name = wxEmptyString );
    wxVariant( short val, const wxString& name = wxEmptyString );
    bool operator== ( long value ) const;
    bool operator!= ( long value ) const;
    void operator= ( long value ) ;
    inline operator long () const {  return GetLong(); }
    inline long GetInteger() const { return GetLong(); }
    long GetLong() const;
    wxVariant( bool val, const wxString& name = wxEmptyString );
    bool operator== ( bool value ) const;
    bool operator!= ( bool value ) const;
    void operator= ( bool value ) ;
    inline operator bool () const {  return GetBool(); }
    bool GetBool() const ;
    wxVariant( const wxDateTime& val, const wxString& name = wxEmptyString );
    bool operator== ( const wxDateTime& value ) const;
    bool operator!= ( const wxDateTime& value ) const;
    void operator= ( const wxDateTime& value ) ;
    inline operator wxDateTime() const { return GetDateTime(); }
    wxDateTime GetDateTime() const;
    wxVariant( const wxString& val, const wxString& name = wxEmptyString );
    wxVariant( const wxChar* val, const wxString& name = wxEmptyString ); // Necessary or VC++ assumes bool!
    bool operator== ( const wxString& value ) const;
    bool operator!= ( const wxString& value ) const;
    void operator= ( const wxString& value ) ;
    void operator= ( const wxChar* value ) ; // Necessary or VC++ assumes bool!
    inline operator wxString() const {  return MakeString(); }
    wxString GetString() const;

    // wxChar
    wxVariant( wxChar val, const wxString& name = wxEmptyString );
    bool operator== ( wxChar value ) const;
    bool operator!= ( wxChar value ) const;
    void operator= ( wxChar value ) ;
    inline operator wxChar() const { return GetChar(); }
    wxChar GetChar() const ;

    // wxArrayString
    wxVariant( const wxArrayString& val, const wxString& name = wxEmptyString );
    bool operator== ( const wxArrayString& value ) const;
    bool operator!= ( const wxArrayString& value ) const;
    void operator= ( const wxArrayString& value );
    inline operator wxArrayString() const { return GetArrayString(); }
    wxArrayString GetArrayString() const;

    // void*
    wxVariant( void* ptr, const wxString& name = wxEmptyString );
    bool operator== ( void* value ) const;
    bool operator!= ( void* value ) const;
    void operator= ( void* value );
    inline operator void* () const {  return GetVoidPtr(); }
    void* GetVoidPtr() const;

    // wxObject*
    wxVariant( wxObject* ptr, const wxString& name = wxEmptyString );
    bool operator== ( wxObject* value ) const;
    bool operator!= ( wxObject* value ) const;
    void operator= ( wxObject* value );
    wxObject* GetWxObjectPtr() const;
    wxVariant( const wxList& val, const wxString& name = wxEmptyString ); // List of variants
    bool operator== ( const wxList& value ) const;
    bool operator!= ( const wxList& value ) const;
    void operator= ( const wxList& value ) ;
    // Treat a list variant as an array
    wxVariant operator[]( size_t idx ) const;
    wxVariant& operator[]( size_t idx ) ;
    wxList& GetList() const ;
    size_t GetCount() const;

    // Make empty list
    void NullList();

    // Append to list
    void Append( const wxVariant& value );

    // Insert at front of list
    void Insert( const wxVariant& value );
    bool Member( const wxVariant& value ) const;
    bool Delete( size_t item );
    void ClearList();

  public:
    bool Convert( long* value ) const;
    bool Convert( bool* value ) const;
    bool Convert( double* value ) const;
    bool Convert( wxString* value ) const;
    bool Convert( wxChar* value ) const;
    bool Convert( wxDateTime* value ) const;
  protected:
    wxVariantData*  m_data;
    wxString        m_name;

  private:
    DECLARE_DYNAMIC_CLASS( wxVariant )
};

#define DECLARE_VARIANT_OBJECT(classname) \
  DECLARE_VARIANT_OBJECT_EXPORTED(classname)

#define DECLARE_VARIANT_OBJECT_EXPORTED(classname) \
  classname& operator << ( classname &object, const wxVariant &variant ); \
  wxVariant& operator << ( wxVariant &variant, const classname &object );

#define IMPLEMENT_VARIANT_OBJECT(classname) \
  IMPLEMENT_VARIANT_OBJECT_EXPORTED(classname, wxEMPTY_PARAMETER_VALUE)

#define IMPLEMENT_VARIANT_OBJECT_EXPORTED_NO_EQ(classname) \
  class classname##VariantData: public wxVariantData \
  { \
    public:\
      classname##VariantData() {} \
      classname##VariantData( const classname &value ) { m_value = value; } \
      \
      classname &GetValue() { return m_value; } \
      \
      virtual bool Eq(wxVariantData& data) const; \
      \
      virtual wxString GetType() const; \
      virtual wxClassInfo* GetValueClassInfo(); \
      \
    protected:\
      classname m_value; \
      \
    private: \
      DECLARE_CLASS(classname##VariantData) \
  };\
  \
  IMPLEMENT_CLASS(classname##VariantData, wxVariantData)\
  \
  wxString classname##VariantData::GetType() const\
  {\
    return m_value.GetClassInfo()->GetClassName();\
  }\
  \
  wxClassInfo* classname##VariantData::GetValueClassInfo()\
  {\
    return m_value.GetClassInfo();\
  }\
  \
  class classname& operator << ( classname &value, const wxVariant &variant )\
  {\
    wxASSERT( wxIsKindOf( variant.GetData(), classname##VariantData ) );\
    \
    classname##VariantData *data = (classname##VariantData*) variant.GetData();\
    value = data->GetValue();\
    return value;\
  }\
  \
  class wxVariant& operator << ( wxVariant &variant, const classname &value )\
  {\
    classname##VariantData *data = new classname##VariantData( value );\
    variant.SetData( data );\
    return variant;\
  }

#define IMPLEMENT_VARIANT_OBJECT_EXPORTED(classname) \
  IMPLEMENT_VARIANT_OBJECT_EXPORTED_NO_EQ(classname) \
  \
  bool classname##VariantData::Eq(wxVariantData& data) const \
  {\
    wxASSERT( wxIsKindOf((&data), classname##VariantData) );\
    \
    classname##VariantData & otherData = (classname##VariantData &) data;\
    \
    return otherData.m_value == m_value;\
  }\

#define IMPLEMENT_VARIANT_OBJECT_SHALLOWCMP(classname) \
  IMPLEMENT_VARIANT_OBJECT_EXPORTED_SHALLOWCMP(classname, wxEMPTY_PARAMETER_VALUE)
#define IMPLEMENT_VARIANT_OBJECT_EXPORTED_SHALLOWCMP(classname) \
  IMPLEMENT_VARIANT_OBJECT_EXPORTED_NO_EQ(classname) \
  \
  bool classname##VariantData::Eq(wxVariantData& data) const \
  {\
    wxASSERT( wxIsKindOf((&data), classname##VariantData) );\
    \
    classname##VariantData & otherData = (classname##VariantData &) data;\
    \
    return (otherData.m_value.IsSameAs(m_value));\
  }\

#define wxGetVariantCast(var,classname) \
  ((classname*)(var.IsValueKindOf(&classname::ms_classInfo) ?\
                var.GetWxObjectPtr() : NULL));

extern wxVariant wxNullVariant;

#endif
